#include<iostream>
#include<vector>
#include<unistd.h>
#include<cstring>
#include<pthread.h>
#include"LockGuard.hpp"
using namespace std ;

#define NUM 4 





// int tickets = 1000; // 票
// class threadData
// {
//         public:
//         threadData ( int number,pthread_mutex_t * mutex ) 
//         {
//                  threadname = "thread-" + to_string(number);
//                  lock =mutex ;
//         }

// public:
//     string  threadname ;  //线程名
//     pthread_mutex_t * lock ;
// } ;

// void * getTicket (void *args )
// {
//             threadData *td = (threadData * ) args ;
//             const char *  name = td->threadname.c_str() ;
//             while(true ) 
//             {
//               //加锁
//               pthread_mutex_lock(td->lock) ;

//               //在加锁和解锁之间的代码是临界区
//              // 申请锁成功，才能往后执行，不成功，阻塞等待。
//                 if(tickets > 0) 
//                 {
//                       usleep(1000);
//                        printf("who=%s, get a ticket: %d\n", name, tickets);
//                     tickets --;
//                        //解锁
//                       pthread_mutex_unlock(td->lock) ;

//                 }
//                 else 
//                 {
//                    //解锁
//                       pthread_mutex_unlock(td->lock) ;
//                        break; 
//                 }
//                    usleep(13);//我们抢到了票，我们会立马抢下一张吗？其实多线程还要执行得到票之后的后续动作。usleep模拟
                   
//             }
//               printf("%s ... quit\n", name);
//             return  nullptr ;

// }
// int main()
// {

//   //互斥锁
//   pthread_mutex_t lock ;
// pthread_mutex_init(&lock ,nullptr) ;


//     vector<pthread_t> tids; 
//     vector<threadData *> thread_datas;  

//     //模拟多线程抢票 
//       for (int i = 1; i <= NUM; i++)
//      {
//          threadData * td   = new threadData (i,&lock);
//         pthread_t tid ;
//           thread_datas.push_back(td);
//         pthread_create(&tid , nullptr ,getTicket , thread_datas[i-1]);
//         tids.push_back(tid) ;
    
//      }
//      //线程等待
//       for (auto thread : tids)
//     {
//         pthread_join(thread, nullptr);
//     }

//   for (auto td : thread_datas)
//     {
//         delete td;
//     }


//     pthread_mutex_destroy(&lock) ;
//     return 0 ;
// }



// pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;//全局的锁，PTHREAD_MUTEX_INITIALIZER是初始化


// int tickets = 1000; // 票
// class threadData
// {
//         public:
//         threadData ( int number) 
//         {
//                  threadname = "thread-" + to_string(number);
      
//         }

// public:
//     string  threadname ;  //线程名
 
// } ;

// void * getTicket (void *args )
// {
//             threadData *td = (threadData * ) args ;
//             const char *  name = td->threadname.c_str() ;
//             while(true ) 
//             {
//                 //加锁
//                  pthread_mutex_lock(&lock) ;
//               //在加锁和解锁之间的代码是临界区
//              // 申请锁成功，才能往后执行，不成功，阻塞等待。
//                 if(tickets > 0) 
//                 {
//                       usleep(1000);
//                        printf("who=%s, get a ticket: %d\n", name, tickets);
//                     tickets --;
//                        //解锁
//                       pthread_mutex_unlock(&lock) ;

//                 }
//                 else 
//                 {
//                    //解锁
//                       pthread_mutex_unlock(&lock) ;
//                        break; 
//                 }
//                    usleep(13);//我们抢到了票，我们会立马抢下一张吗？其实多线程还要执行得到票之后的后续动作。usleep模拟
                   
//             }
//               printf("%s ... quit\n", name);
//             return  nullptr ;

// }
// int main()
// {




//     vector<pthread_t> tids; 
//     vector<threadData *> thread_datas;  

//     //模拟多线程抢票 
//       for (int i = 1; i <= NUM; i++)
//      {
//          threadData * td   = new threadData (i);
//         pthread_t tid ;
//           thread_datas.push_back(td);
//         pthread_create(&tid , nullptr ,getTicket , thread_datas[i-1]);
//         tids.push_back(tid) ;
    
//      }
//      //线程等待
//       for (auto thread : tids)
//     {
//         pthread_join(thread, nullptr);
//     }

//   for (auto td : thread_datas)
//     {
//         delete td;
//     }


//     pthread_mutex_destroy(&lock) ;
//     return 0 ;
// }



pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;//全局的锁，PTHREAD_MUTEX_INITIALIZER是初始化


int tickets = 1000; // 票
class threadData
{
        public:
        threadData ( int number) 
        {
                 threadname = "thread-" + to_string(number);
      
        }

public:
    string  threadname ;  //线程名
 
} ;

void * getTicket (void *args )
{
            threadData *td = (threadData * ) args ;
            const char *  name = td->threadname.c_str() ;
            while(true ) 
            {

               {
                        //加锁
                    LockGuard lockguard (&lock) ;// 临时的LockGuard对象， RAII风格的锁！


                  //在加锁和解锁之间的代码是临界区
                // 申请锁成功，才能往后执行，不成功，阻塞等待。
                    if(tickets > 0) 
                    {
                          usleep(1000);
                          printf("who=%s, get a ticket: %d\n", name, tickets);
                        tickets --;
                
                    }
                    else 
                    {

                          break; 
                    }
               }  //走出花括号 ，自动调用 ~LockGuard析构函数来解锁

                   usleep(13);//我们抢到了票，我们会立马抢下一张吗？其实多线程还要执行得到票之后的后续动作。usleep模拟
                   
            }
              printf("%s ... quit\n", name);
            return  nullptr ;

}
int main()
{




    vector<pthread_t> tids; 
    vector<threadData *> thread_datas;  

    //模拟多线程抢票 
      for (int i = 1; i <= NUM; i++)
     {
         threadData * td   = new threadData (i);
        pthread_t tid ;
          thread_datas.push_back(td);
        pthread_create(&tid , nullptr ,getTicket , thread_datas[i-1]);
        tids.push_back(tid) ;
    
     }
     //线程等待
      for (auto thread : tids)
    {
        pthread_join(thread, nullptr);
    }

  for (auto td : thread_datas)
    {
        delete td;
    }


    pthread_mutex_destroy(&lock) ;
    return 0 ;
}